package edu.mit.csail.relo.jdt.builder.asm;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;

import edu.mit.csail.relo.ReloCore;
import edu.mit.csail.relo.jdt.RJCore;
import edu.mit.csail.relo.store.ReloRdfRepository;

/**
 * @author Cyrus J. Kalbrener
 * @version 1.0
 */
public class AsmMethodVisitor implements MethodVisitor {

	//private static final Logger logger = ReloJDTPlugin.getLogger(AsmMethodVisitor.class);

	private final AnnotationVisitor annotationVisitor;

    private static final URI createReloURI(String str) {
    	return ReloCore.createReloURI(str);
    }
	static final URI anonymousMethodType = createReloURI("jdt#anonymousMethod");

	// private volatile int sourceEnd = -1;
	// private volatile int sourceStart = -1;
	private Resource methodKey;

	private ReloRdfRepository reloRdf;
	
	public AsmMethodVisitor(ReloRdfRepository rrr, Resource methodKey) {
		reloRdf = rrr;
		this.annotationVisitor = new AsmAnnotationVisitor(rrr);
		this.methodKey = methodKey;
	}

	public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
		return annotationVisitor;
	}

	public AnnotationVisitor visitAnnotationDefault() {
		return annotationVisitor;
	}

	public void visitAttribute(Attribute attr) {
	}

	public void visitCode() {
	}

	public void visitEnd() {
		reloRdf.addStatement(methodKey, ReloCore.initialized, true);
	}

	public void visitFieldInsn(int opcode, String owner, String name, String desc) {
		Resource fieldKey = AsmUtil.toReloResource(reloRdf, AsmUtil.getRdfClassName(owner) + "." + name);
		reloRdf.addStatement(methodKey, RJCore.refType, fieldKey);
	}

	public void visitIincInsn(int var, int increment) {
	}

	public void visitInsn(int opcode) {
	}

	public void visitIntInsn(int opcode, int operand) {
	}

	public void visitJumpInsn(int opcode, Label label) {
	}

	public void visitLabel(Label label) {
	}

	public void visitLdcInsn(Object cst) {
	}

	public void visitLineNumber(int line, Label start) {
		// if(sourceStart < 0) {sourceStart = line;}
		//
		// if(sourceEnd < line) {sourceEnd = line;}
	}

	public void visitLocalVariable(
			String name, String desc, String signature,
			Label start, Label end, int index) {
		reloRdf.addStatement(methodKey, RJCore.refType, AsmUtil.toReloClassResource(reloRdf, Type.getType(desc)));
	}

	public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
	}

	public void visitMaxs(int maxStack, int maxLocals) {
	}

	// visit a 'method instruction', i.e. handle method class 
	public void visitMethodInsn(int opcode, String owner, String name, String desc) {
		// Ignore opcode. We don't really care
		Type ownerType = AsmUtil.internalNameToType(owner);

		if (owner.equals(AsmClassVisitor.OBJECT_TYPE_NAME) && name.equals("<init>")) {
			return;
		}

		int idx = name.lastIndexOf('$');
		if (idx != -1) name = name.substring(idx + 1);
		// {these seem to be anonymous *methods* generated by the compiler}

		StringBuilder buff = new StringBuilder(AsmUtil.getRdfClassName(owner)).append('.');

		if (name.equals("<init>")) {
			name = ownerType.getClassName();
			name = name.substring(name.lastIndexOf('.') + 1);
		}

		buff.append(AsmUtil.getMethodSignature(name, desc));

		Resource calledMethodKey = reloRdf.getDefaultURI(RJCore.jdtWkspcNS, buff.toString());
		reloRdf.addStatement(methodKey, RJCore.calls, calledMethodKey);
		reloRdf.addStatement(methodKey, RJCore.refType, calledMethodKey);
		reloRdf.addStatement(methodKey, RJCore.refType, AsmUtil.toReloClassResource(reloRdf, ownerType));

		for (Type t : Type.getArgumentTypes(desc)) {
			reloRdf.addStatement(methodKey, RJCore.refType, AsmUtil.toReloClassResource(reloRdf, t));
		}
		reloRdf.addStatement(methodKey, RJCore.refType, AsmUtil.toReloClassResource(reloRdf, Type.getReturnType(desc)));
	}

	public void visitMultiANewArrayInsn(String desc, int dims) {
	}

	public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
		return annotationVisitor;
	}

	public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
	}

	public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
	}

	public void visitTypeInsn(int opcode, String desc) {
		Resource typeResource = AsmUtil.toReloClassResource(reloRdf, AsmUtil.internalNameToType(desc));
		reloRdf.addStatement(methodKey, RJCore.refType, typeResource);
	}

	public void visitVarInsn(int opcode, int var) {
	}
}
